package gui;


import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

import maze.Barcode;
import maze.Coordinate;
import maze.Direction;
import maze.Maze;
import pacman.Game;

import robots.Ghost;

import robots.Ghost;
import robots.OwnGhost;
import robots.VirtualGhost;
import robots.behaviour.Explorer;
import robots.behaviour.PacmanFinder;
import simulation.ColorMap;
import simulation.Simulator;




/**
 * Represent one ghost and creates a new GUI in a new frame for this robot.
 *
 *
 */
@SuppressWarnings("serial")
public class GhostPanel extends JPanel{
	private  boolean DRAWFOG = true;
	BufferedImage sector;
	BufferedImage pacman;
	BufferedImage background;
	BufferedImage map;
	BufferedImage colormap;
	BufferedImage robot;
	BufferedImage blackScreen;
	BufferedImage robotrotated;
	BufferedImage fog;
	BufferedImage ultrasonic;
	BufferedImage backgroundPanel = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
	BufferedImage panel = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
	BufferedImage mazeImg;
	private static final int FPS = 5;
	String log = "";
	Ghost ghost;
	Game game;
	ComponentFrame frame;
	Timer t;
	private HashMap<String, BufferedImage> imgs = new HashMap<String, BufferedImage>();

	


	


	public GhostPanel(Ghost ghost,Game game,BufferedImage ghostImg)
	{
		this.game = game;
		this.ghost = ghost;
		loadImages();
		if( ghostImg != null)
			this.robot = ghostImg;
		robot = Graphic.scale(robot,0.5);
		
		
		setMinimumSize(new Dimension(800,600));
		setMaximumSize(new Dimension(1900,1080));
		setPreferredSize(new Dimension(800,600));
		setLocation(200,200);
		setSize(getPreferredSize());
		
		drawBackground();
		
		
		t = new Timer(1000/FPS, new ActionListener(){

			//timer to set when to draw the screen and update values
			@Override
			public void actionPerformed(ActionEvent arg0) {
				if (isShowing())
					draw();
			}

		});
		t.start();
		KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
		manager.addKeyEventDispatcher(new MyDispatcher());
		frame = new ComponentFrame(ghost.getName(), this,JFrame.DISPOSE_ON_CLOSE);
		updateMaze();
	}


	public void setImgs(HashMap<String, BufferedImage> imgs) {
		this.imgs = imgs;
	}
	
	/**
	 * draws the maze for this ghost.
	 * @param m
	 * 			The image to draw on
	 * @param ghostMaze
	 * 			The maze the ghost knows
	 * @return
	 * 			A new image that displays the maze
	 */
	private BufferedImage drawGhostMaze(BufferedImage m, Maze ghostMaze) {
		int maxX = ghostMaze.getMaxX() + 1;
		int maxY = ghostMaze.getMaxY() + 1;
		int minX = ghostMaze.getMinX();
		int minY = ghostMaze.getMinY();
		int minXWrap = ghostMaze.getMinXWrap();
		int minYWrap = ghostMaze.getMinYWrap();
		int size = ghostMaze.getSize();

		// the image to draw the whole maze onto, even the white space

		BufferedImage temp = new BufferedImage(40 * (int) (ghostMaze.getRawData()[0].length / 2) + 40, 40 * ghostMaze.getRawData().length, BufferedImage.TYPE_INT_ARGB);

		BufferedImage fogofwar = new BufferedImage(40 * (int) (ghostMaze.getRawData()[0].length / 2) + 40, 40 * ghostMaze.getRawData().length, BufferedImage.TYPE_INT_ARGB);
		Graphics2D map = (Graphics2D) temp.getGraphics();
		map.setStroke(new BasicStroke(2f));
		Graphics fogfwar = fogofwar.getGraphics();
				// draw sectors
		drawSectors(size, map);
		char[][] mazeToDraw = ghostMaze.getRawData();
		char[][] data = mazeToDraw;
		
//		drawSectors(size, map);
//		drawBarcodes(ghostMaze, map, data);
		drawWallsAndFog(maxX, size, temp, map, fogfwar, data);
		
		
		if(DRAWFOG)
			map.drawImage(fogofwar, 0, 0, null);
		map.dispose();
		
		
		BufferedImage temp2 = new BufferedImage((maxX - minX) * 40, (maxY - minY) * 40, BufferedImage.TYPE_INT_ARGB);
		Graphics gr = temp2.getGraphics();

		fixWraparound(m, maxX, maxY, minX, minY, temp, temp2, gr);
		
		try{
		Maze diffusionMaze = null;
		if(((OwnGhost)ghost).getCurrentStrategy() instanceof PacmanFinder) diffusionMaze = ((PacmanFinder)((OwnGhost)ghost).getCurrentStrategy()).collaborativeDiffusionMaze;
		if(diffusionMaze!=null ) {
			gr = m.getGraphics();
			int iiy = 0;
			int iix = 0;
			for(int iy = maxY-1; iy>=minY; iy--) {
				for(int ix = minX; ix<=maxX-1; ix++) {
					int diffusionValue = diffusionMaze.read(ix, iy, Direction.NORTH, true) - diffusionMaze.read(ix, iy, Direction.EAST, true) - (65535-16);
					diffusionValue *= 16;
					diffusionValue = Math.max(Math.min(255, diffusionValue),0);
					gr.setColor(new Color(diffusionValue, diffusionValue, diffusionValue, 128));
					gr.fillRect(iix*40, iiy*40, 40, 40);
					iix++;
				}
				iiy++;
				iix=0;
			}
			gr.dispose();
		}}catch(Exception e){}
		
		return m;
	}


	/**
	 * draw all the movable objects on the screen.
	 */
	private BufferedImage drawActors(BufferedImage m, Maze ghostMaze) {
		int maxX = ghostMaze.getMaxX() + 1;
		int maxY = ghostMaze.getMaxY() + 1;
		int minX = ghostMaze.getMinX();
		int minY = ghostMaze.getMinY();

		int size = ghostMaze.getSize();

		// the image to draw the whole maze onto, even the white space

		BufferedImage temp = new BufferedImage(40 * (int) (ghostMaze.getRawData()[0].length / 2) + 40, 40 * ghostMaze.getRawData().length, BufferedImage.TYPE_INT_ARGB);
		Graphics2D map = (Graphics2D) temp.getGraphics();
		map.setStroke(new BasicStroke(2f));
		

		char[][] mazeToDraw = ghostMaze.getRawData();
		char[][] data = mazeToDraw;
		//drawSectors(size, map);
		drawBarcodes(ghostMaze, map, data);
		//draw Pacman here
		if(ghost.hasFoundPacman()) {
			drawPacman(size, map);
		}
		
		//robot draw here
		//TODO change back into game coordinates if this is initiated
		drawRobot(size, map);

	
		
		map.dispose();
		BufferedImage temp2 = new BufferedImage((maxX - minX) * 40, (maxY - minY) * 40, BufferedImage.TYPE_INT_ARGB);
		Graphics gr = temp2.getGraphics();

		fixWraparound(m, maxX, maxY, minX, minY, temp, temp2, gr);
		gr.dispose();
		
		return m;
	}

	/**
	 * returns the difference in position of the barcode according to own coordinates in maze
	 * @return
	 */
	private Coordinate getDifferenceBarcodes(Maze orig, Maze other){
		for (Barcode b : other.getBarcodes()) {
			for (Barcode b2 : orig.getBarcodes()) {
				if (b.getCode().equals(b2.getCode())){
					return new Coordinate(b2.getX()-b.getX(), b2.getY()-b.getY());
				}
			}
		}
		return null;
	}
	
	
	private void drawRobot(int size, Graphics2D map) {
		int x = 0;
		int y = 0;
		map.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);

		
	
	//draw other ghosts
			//the f*ck is this?
			/*for (Ghost g : game.getGhosts()) {
				
				//if (!simulator.getGhostLocations().keySet().contains(g)){
					try{
					//if (origin.alreadyMatchedMaze(g.getMaze())){
						if (!g.equals(this.ghost)){
						Coordinate bDiff = getDifferenceBarcodes(this.ghost.getMaze(), g.getMaze());
						
						//						int x = diff.x + origin.getCoordinate().x ;//+ bDiff.x;
//						int y = diff.y + origin.getCoordinate().y ;//+ bDiff.y;
						 x = bDiff.x + game.getGhostPositions().get(g).x ;
						 y = game.getGhostPositions().get(g).y + bDiff.y;
						x = (int) positivemodulo(x, (size + 1));
						y = (int) positivemodulo(y, (size + 1));
						
						y = size  - y;
						
						map.drawImage(imgs.get(g.getName()), (int) ((x)*40 ) , (int) ((y)*40 ) ,40, 40, null);
					
						}
					//}
					}catch(Exception e){}
				//}
			}*/
		
		for (Ghost g : game.getGhosts()) {
				try{
					if (!g.equals(this.ghost) && this.ghost.alreadyMatchedGhost(g)){
					Coordinate temp = this.ghost.getMazeOnName(g.getName()).reverseTransform(game.getGhostPositions().get(g)); 
					x = temp.x;
					y = temp.y;
					System.out.println(g.getName() + ": " + temp);
					x = (int) positivemodulo(x, (size + 1));
					y = (int) positivemodulo(y, (size + 1));
					y = (size)   - y;
					
					map.drawImage(imgs.get(g.getName()), (int) ((x)*40 ) , (int) ((y)*40) ,40, 40, null);
					map.drawString(x + ", " + y, (int) ((x)*40 ), (int) ((y)*40 +20));
					}
				}catch(Exception e){throw new RuntimeException();}
		}
	
			try{

				 x = game.getGhostPositions().get(this).x;
				 y = game.getGhostPositions().get(this).y;
				// x = Math.abs(x%(data.length-1));
				x = (int) positivemodulo(x, (size ));
				y = (int) positivemodulo(y, (size ));
				y = (size)  -1 - y;
				
				
			
				
				//map.drawImage(robot, (int) ((x)*40 ) , (int) ((y)*40 ) ,40, 40, null);
				//map.drawString(x + ", " + y, (int) ((x)*40 ) , (int) ((y+1)*40 )-20 );
				}catch(Exception e) {
					try{
					x = game.getGhostPositions().get(this.ghost).x;
					y = game.getGhostPositions().get(this.ghost).y;
					}
				catch(NullPointerException e2){

					System.out.println("game.getGhospositions() returns null location!");
					return;
				}
					}
					// x = Math.abs(x%(data.length-1));
					x = (int) positivemodulo(x, (size + 1));
					y = (int) positivemodulo(y, (size + 1));
					y = (size)   - y;
//					System.out.println( x + "," + y);
					map.setColor(Color.RED);
					
					map.drawImage(robot, (int) ((x)*40 ) , (int) ((y)*40 ) ,40, 40, null);
					map.drawString(x + ", " + y, (int) ((x)*40 ), (int) ((y)*40 +20));
					//map.drawString(x + ", " + (y-size), (int) ((x)*40 ) , (int) ((y+1)*40 )-20 );
			
	
	}


	private void drawPacman(int size, Graphics2D map) {
		
		
		if(!(ghost.getCoordinatePacman() == null))
		{
			
		double x = (ghost.getCoordinatePacman().x  );
		double y = (ghost.getCoordinatePacman().y);
//note pacman coordinate seems to be null all the time.
		x = (int) positivemodulo(x, (size + 1));
		y = (int) positivemodulo(y, (size + 1));
		y = (size)  - y;
		
		map.drawImage(pacman, (int) ((x)*40 ) , (int) ((y)*40 ) , 40,40 ,null);
		}
	}
	
	/**
	 * set the pieces of the maze at the right position.
	 * @return
	 */
	private void fixWraparound(BufferedImage m, int maxX, int maxY,
			int minX, int minY, BufferedImage temp, BufferedImage temp2,
			Graphics gr) {
		int d_width = temp2.getWidth();
		int d_height = temp2.getHeight();
		int d_xborder = -minX * 40;
		int d_yborder = maxY * 40;

		int s_width = temp.getWidth();
		int s_height = temp.getHeight();
		int s_xmax = maxX * 40;
		int s_ymax = s_height - maxY * 40;
		int s_xminwrap = s_width + minX * 40;
		int s_yminwrap = -minY * 40;

		// x-y-
		gr.drawImage(temp, 0, d_yborder, d_xborder, d_height, s_xminwrap, 0, s_width, s_yminwrap, null);
		// x+y+
		gr.drawImage(temp, d_xborder, 0, d_width, d_yborder, 0, s_ymax, s_xmax, s_height, null);
		// x-y+
		gr.drawImage(temp, 0, 0, d_xborder, d_yborder, s_xminwrap, s_ymax, s_width, s_height, null);
		// x+y-
		gr.drawImage(temp, d_xborder, d_yborder, d_width, d_height, 0, 0, s_xmax, s_yminwrap, null);
		gr.dispose();

		gr = m.getGraphics();
		gr.setColor(Color.BLACK);
		gr.drawImage(temp2, 0, 0, null);
		gr.fillRect(temp2.getWidth(), 0, m.getWidth(), m.getHeight());
		gr.fillRect(0, temp2.getHeight(), m.getWidth(), m.getHeight());
		gr.dispose();
		
	}

	private void drawWallsAndFog(int maxX, int size, BufferedImage temp,
			Graphics2D map, Graphics fogfwar, char[][] data) {
		// draw walls and fog
		map.setColor(new Color(90, 43, 0));
		int YStart = 0;
		int XStart = 0;
		boolean xskipped = false;
		

		// draw walls and fog on top row
		for (int x = 0; x < (2 * size + 1); x++) {
			int yy = data.length - 1;
			if (!xskipped && !(((x - 1) / 2) < maxX)) {
				XStart += 40;
				xskipped = true;
			}
			if (data[yy][x] == 1) {
				if (x % 2 != 0) {
					if (((x - 1) / 2) < maxX) {
						map.drawLine(XStart, YStart, XStart + 40, YStart);
						XStart += 40;
					}
				} else {
					if (!(((x - 1) / 2) < maxX)) {
						map.drawLine(XStart, YStart, XStart + 40, YStart);
						XStart += 40;
					}
				}
			} else if (data[yy][x] == 0) {
				;
				if (x % 2 != 0) {
					if (((x - 1) / 2) < maxX) {
						fogfwar.drawImage(fog, XStart, YStart - 20, null);
						XStart += 40;
					}
				} else {
					if (!(((x - 1) / 2) < maxX)) {
						fogfwar.drawImage(fog, XStart, YStart - 20, null);
						XStart += 40;
					}
				}
			} else {
				if (x % 2 != 0) {
					if (((x - 1) / 2) < maxX)
						XStart += 40;
				} else {
					if (!(((x - 1) / 2) < maxX))
						XStart += 40;
				}
			}
		}
		XStart = 0;
		YStart = 40;
		xskipped = false;

		// draw all the other walls and fog
		for (int y = 0; y < size + 1; y++) {
			for (int x = 0; x < (2 * size + 1); x++) {
				if (!xskipped && !(((x - 1) / 2) < maxX)) {
					XStart += 40;
					xskipped = true;
				}
				if (data[y][x] == 1) {
					if (x % 2 != 0) {
						if (((x - 1) / 2) < maxX) {
							map.drawLine(XStart, YStart, XStart + 40, YStart);
							XStart += 40;
						} else {
							map.drawLine(XStart, YStart, XStart, YStart - 40);
						}
					} else {
						if (((x - 1) / 2) < maxX) {
							map.drawLine(XStart, YStart, XStart, YStart - 40);
						} else {
							map.drawLine(XStart, YStart, XStart + 40, YStart);
							XStart += 40;
						}
					}
				} else if (data[y][x] == 0) {
					;
					if (x % 2 != 0) {
						if (((x - 1) / 2) < maxX) {
							fogfwar.drawImage(fog, XStart, YStart - 20, null);
							XStart += 40;
						} else {
							fogfwar.drawImage(fog, XStart - 20, YStart - 40, null);
						}
					} else {
						if (((x - 1) / 2) < maxX) {
							fogfwar.drawImage(fog, XStart - 20, YStart - 40, null);
						} else {
							fogfwar.drawImage(fog, XStart, YStart - 20, null);
							XStart += 40;
						}
					}
				} else {
					if (x % 2 != 0) {
						if (((x - 1) / 2) < maxX) {
							XStart += 40;
						}
					} else {
						if (!(((x - 1) / 2) < maxX)) {
							XStart += 40;
						}
					}
				}
			}
			YStart += 40;
			XStart = 0;
			xskipped = false;
		}
		YStart = 40;
		XStart = temp.getWidth();
		// draw the right column
		for (int y = 0; y < size + 1; y++) {
			if (data[y][0] == 1) {
				map.drawLine(XStart, YStart, XStart, YStart - 40);
			} else if (data[y][0] == 0) {
				;
				fogfwar.drawImage(fog, XStart - 20, YStart - 40, null);
			}
			YStart += 40;
		}
		//robot draw here
		

		fogfwar.dispose();
	}

	private void drawBarcodes(Maze ghostMaze, Graphics2D map, char[][] data) {
		try{
		for (Barcode code : ghostMaze.getBarcodes()) {
			

			int x = code.getPosition().getX();
			int y = code.getPosition().getY();

			x = (int) positivemodulo(x, (ghostMaze.getSize() + 1));
			y = (int) positivemodulo(y, (ghostMaze.getSize() + 1));
			
			
			 y = data.length  -1 - y;
			
			
			char[] bcode = new char[code.getCode().length()];
			for (int i = 0; i < bcode.length; i++) {
				bcode[i] = code.getCode().charAt(i);
			}

			int dir = code.getDirection();
			//reverse if needed
			if (dir == 3 || dir == 2) {
				for(int i = 0; i<bcode.length/2; i++) {
					char temp = bcode[i];
					bcode[i] = bcode[bcode.length-1-i];
					bcode[bcode.length-1-i] = temp;
				}
			}
			
			if (dir == 1 || dir == 3)
				drawBarcode(map, x, y, bcode, true);
			else
				drawBarcode(map, x, y, bcode, false);

		}
		}catch(Exception e){
		}
	}

	private void drawSectors(int size, Graphics2D map) {
		for (int i = 0; i < size + 1; i++) {
			for (int j = 0; j < size + 1; j++) {
				double YStartPos = (i) * 40;
				double XStartPos = (j) * 40;
				map.drawImage(sector, (int) XStartPos, (int) YStartPos, null);
			}
		}
	}
	
	
	private void drawBackground() {
		Graphics2D g =  backgroundPanel.createGraphics();
	for (int i = 0; i < 3; i++) {
		for (int j = 0;j < 2; j++) {
			g.drawImage(background, i*300, j*300, (i+1)*300, (j+1)*300, 0, 0, 350, 350, null);
		}
	}		
	g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);

		g.setColor(Color.BLACK);
		g.fillRect(600, 0, 200, 300);
		g.drawImage(robot, 600, 0,200,300 ,null);
		g.dispose();
	}
	
	/**
	 * Draws a barcode at a given position on an image, draws from left to right
	 * or up to down.
	 * 
	 * @param g
	 *            |The graphics to paint on
	 * @param x
	 *            |The X position of the tile where to draw the barcode
	 * @param y
	 *            |The Y position of the tile where to draw the barcode
	 * @param code
	 *            |The actual barcode to draw
	 * @param hor
	 *            |Boolean to indicate if the code is horizontal or vertical
	 */
	private void drawBarcode(Graphics g, int x, int y, char[] code, boolean hor) {
		((Graphics2D)g).setStroke(new BasicStroke(2.0f));
		if (hor) {
			for (int i = 0; i < code.length; i ++) {

				if (code[i] == '0')
					g.setColor(new Color(0, 0, 0));
				else
					g.setColor(new Color(255, 255, 255));

				g.drawLine(x * 40, (y * 40) + code.length + 3 + i*2, (x + 1) * 40, (y * 40) + code.length + 3 + i*2);
			}

		} else {
			for (int i = 0; i < code.length; i ++) {
				if (code[i] == '0')
					g.setColor(new Color(0, 0, 0));
				else
					g.setColor(new Color(255, 255, 255));

				g.drawLine(x * 40 + code.length + i*2+ 3, (y * 40), (x) * 40 + code.length + i*2 + 3, ((y + 1) * 40));
			}
		}
	}

	
	
	public void showFrame(){
		
		frame.setVisible(true);
	}
	
	public void hideFrame(){
		
		frame.setVisible(false);
	}
	
	/**
	 * Loads the images used
	 */
	public void loadImages() {
		try {
			sector = ImageIO.read(new File("gui/sector_rand.png"));
			pacman = ImageIO.read(new File("gui/pacman.png"));
			background = ImageIO.read(new File("gui/wood.jpg"));
			robot = ImageIO.read(new File("gui/robot.png"));
			blackScreen = ImageIO.read(new File("gui/DataScreenRobot.png"));
			robotrotated = ImageIO.read(new File("gui/robot.png"));
			fog = ImageIO.read(new File("gui/fogofwar.png"));
			ultrasonic = ImageIO.read(new File("gui/ultrasonic.png"));

		} catch (IOException ex) {
			try {
				sector = ImageIO.read(new File("..\\PenOGuiFiles\\sector_rand.png"));
				pacman = ImageIO.read(new File("..\\PenOGuiFiles\\pacman.png"));
				background = ImageIO.read(new File("..\\PenOGuiFiles\\wood.jpg"));
				robot = ImageIO.read(new File("..\\PenOGuiFiles\\robot.png"));
				blackScreen = ImageIO.read(new File("..\\PenOGuiFiles\\DataScreenRobot.png"));
				robotrotated = ImageIO.read(new File("..\\PenOGuiFiles\\robot.png"));
			} catch (IOException e) {
				try {
					sector = ImageIO.read(new File("../PenOTiles/sector_rand.png"));
					pacman = ImageIO.read(new File("../PenOTiles/pacman.png"));
					background = ImageIO.read(new File("../PenOTiles/wood.jpg"));
					robot = ImageIO.read(new File("../PenOTiles/robot.png"));
					blackScreen = ImageIO.read(new File("../PenOTiles/DataScreenRobot.png"));
					robotrotated = ImageIO.read(new File("../PenOTiles/robot.png"));
					fog = ImageIO.read(new File("../PenOTiles/fogofwar.png"));
					ultrasonic = ImageIO.read(new File("../PenOTiles/ultrasonic.png"));
				} catch (IOException e1) {
					System.out.println("file not found in GhostPanel");
				}

			}
		}
		robot = Graphic.scale(robot, 0.75);
	}
	
	/**
	 * redraw the maze if it has been changed
	 */
	public void updateMaze(){
		Maze maze = ghost.getMaze();
		int width = maze.getSize();
		 mazeImg = new BufferedImage(40 * width, 40 * width, BufferedImage.TYPE_INT_ARGB);	
		mazeImg = drawGhostMaze(mazeImg, maze);
		
	}
	
	/**
	 * put draw code here.
	 */
	private void draw() {
		
//	if (ghost.getMaze().changed())
		updateMaze();
	Graphics g = panel.getGraphics();
	g.drawImage(backgroundPanel,0,0,null);
	g.setColor(Color.WHITE);
	g.setFont(new Font("Ariel", Font.BOLD, 12));
	drawString(g,log, 610, 0);
		
		
		Maze maze = ghost.getMaze();
		int width = maze.getSize();
		BufferedImage botMap = new BufferedImage(40 * width, 40 * width, BufferedImage.TYPE_INT_ARGB);	
		
		((Graphics2D)g).setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
		botMap = drawActors(botMap, maze);
		
		g.drawImage(mazeImg, 0, 0, 600, 600, null);
		g.drawImage(botMap, 0, 0, 600, 600, null);
		g.dispose();
		repaint();
		
	}
	
	  private void drawString(Graphics g, String text, int x, int y) {
	        for (String line : text.split("\n"))
	            {
	        	if (y > 300-g.getFontMetrics().getHeight())
	        		return;
	        	g.drawString(line, x, y += g.getFontMetrics().getHeight());
	            
	            }
	    }
	
	/**
	 * The code to paint on the screen.
	 */
	@Override
	public void paintComponent(Graphics g){
		g.drawImage(panel,0,0,this.getWidth(),this.getHeight(),null);
	}
	
	/**
	 * What to do when repaint() gets called.
	 */
	@Override
	public void update(Graphics g){
		paint(g);
	}
	
	private double positivemodulo(double val, double mod) {
		mod = Math.abs(mod); // no negative modulo allowed
		mod = (mod == 0) ? 1 : mod; // no zero modulo either
		while (val < 0)
			val += mod; // increase val until we're sure it's positive
		return val % mod;
	}

	
	public static void main(String args[]) throws IOException{
		Game game = new Game();

	
		
		
	

		Maze maze = new Maze(5);
		ColorMap colormap = new ColorMap();
		colormap.setupMap(maze, 5, 5);
		Simulator sim = new Simulator(new Maze(10), colormap);
		VirtualGhost ghostt = new VirtualGhost(game, "Jos", sim);
		VirtualGhost ghostt2 = new VirtualGhost(game, "Jos", sim);
		VirtualGhost ghostt3 = new VirtualGhost(game, "Jos", sim);
		VirtualGhost ghostt4 = new VirtualGhost(game, "Jos", sim);
		OwnGhost[] ghosts = {ghostt,ghostt2,ghostt3,ghostt4};
		game.addFourOwnGhost(ghosts);

		//GhostPanel panel1 = new GhostPanel(ghostt,game);
		ghostt.getMaze().addBarcode(new Coordinate(0,0), "10001000", 1);

//		ghostt.setStrategy(new Explorer(ghostt.getMaze()));
//		ghostt.setCoordinatePacman(new Coordinate(0, 0));

		ghostt.setCoordinatePacman(new Coordinate(0, 0));

//		GhostPanel panel4 = new GhostPanel("jef");

	}
	
	private class MyDispatcher implements KeyEventDispatcher {
		@Override
		public boolean dispatchKeyEvent(KeyEvent e) {

		 if (e.getID() == KeyEvent.KEY_RELEASED) {

				int keyCode = e.getKeyCode();
//				switch (keyCode) 
//				{
//				case KeyEvent.VK_UP:
//					log="DISCOVER SHIT\n" + log;	
//					break;			
//				case KeyEvent.VK_DOWN:
//					log="BARCODEAT 4984\n" + log;
//					break;
//				case KeyEvent.VK_LEFT:
//					log="PING\n" + log;
//					break;		
//				case KeyEvent.VK_RIGHT:
//					log="PONG\n" + log;
//					break;
//				case KeyEvent.VK_BACK_SPACE:
//					DRAWFOG = !DRAWFOG;
//					updateMaze();
//					break;
//				}
		}
			
			return false;
		}
	}
	
}
